#include <stdio.h>
#include <stdlib.h>
#include "CPU.h"
#include "Cache.h"


void readFile(char *path) {
	int counter = 0;
	FILE * pFile;
	char inputLine[10];

	pFile = fopen(path, "r");
	if (pFile == NULL) {
		perror("Error opening file");
	} else {
		while (counter < 256 && fgets(inputLine, 10, pFile) != NULL) {

			int command = 0;
			int operand = 0;

			sscanf(inputLine, "%x %x", &command, &operand);

			writeToDataCache(counter, operand);
			writeToInstructionCache(counter, command);

			counter++;

			numberOfLines = counter;
		}
		fclose(pFile);
	}
}

void STA(int value) {
	writeToDataCache(value, akkumulator);
}

void LDAREF(int value) {
	akkumulator = readDataCache(value);
}

void LDA(int value) {
	akkumulator = value;
}

void NOP() {
}

void setStatusBits() {
	if (akkumulator == 0) {
		zeroBit = 1;
	}
	if (akkumulator < 0) {
		negativeBit = 1;
	}
}
void carryCheck(int value) {
	if ((akkumulator + value) > 127 || (akkumulator - value) < 128) {
		carryBit = 1;
	}
}

void ADDREF(int value) {

	int operand = readDataCache(value);
	carryCheck(operand);
	akkumulator += operand;
	setStatusBits();
}
void ADD(int value) {
	carryCheck(value);

	akkumulator += value;
	setStatusBits();
}
void SUBBREF(int value) {
	int operand = readDataCache(value);
	carryCheck(operand);
	akkumulator -= operand;
	setStatusBits();
}
void SUBB(int value) {
	carryCheck(value);
	akkumulator -= value;
	setStatusBits();
}

void JMP(int value) {
	if (value < numberOfLines) {
		programCounter = value;
	} else {
		printf("error: can't jump to line %d => maximum lineNumber = %d \n",
				value, (numberOfLines - 1));
	}
}
void BRZ(int value) {
	if (zeroBit == 1) {
		programCounter += value;
	}
}
void BRC(int value) {
	if (carryBit == 1) {
		programCounter += value;
	}
}

void BRN(int value) {
	if (negativeBit == 1) {
		programCounter += value;
	}

}
void Fetch(int currentLine) {
	currentCommand = readInstructionCache(currentLine);
	currentValue = readDataCache(currentLine);
}


void DecodeAndExecute() {

	switch (currentCommand) {
	case 0:
		NOP();
		break;

	case 1:
		LDA(currentValue);
		break;
	case 2:
		LDAREF(currentValue);
		break;

	case 3:
		STA(currentValue);
		break;

	case 4:
		ADD(currentValue);
		break;
	case 5:
		ADDREF(currentValue);
		break;

	case 6:
		SUBB(currentValue);
		break;
	case 7:
		SUBBREF(currentValue);
		break;

	case 8:
		JMP(currentValue);
		break;

	case 9:
		BRC(currentValue);
		break;
	case 10:
		BRZ(currentValue);
		break;
	case 11:
		BRN(currentValue);
		break;
	}


}

void ExecuteProgramm() {
	int i;
	for (i = 0; i < numberOfLines; i++) {
		Fetch(i);
		DecodeAndExecute();
	}
}

void printCache() {
	int i;
	for (i = 0; i < numberOfLines; i++) {
		printf("instruction= %x", readInstructionCache(i));
		printf("\toperand= %x\n", readDataCache(i));
	}
}

int main(int argc, char *argv[]) {

	readFile("output.txt");
	printCache();

	ExecuteProgramm();

	return 0;
}

